home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Panorama / Panorama - Disk 19D (1987-07-22)(Pacific North-West Amigas Club)[WB].zip / Panorama - Disk 19D (1987-07-22)(Pacific North-West Amigas Club)[WB].adf / PipeHandler1.2 / pipecreate.c < prev    next >
C/C++ Source or Header  |  1987-06-28  |  14KB  |  487 lines

  1. /****************************************************************************
  2. **  File:       pipecreate.c
  3. **  Program:    pipe-handler - an AmigaDOS handler for named pipes
  4. **  Version:    1.1
  5. **  Author:     Ed Puckett      qix@mit-oz
  6. **
  7. **  Copyright 1987 by EpAc Software.  All Rights Reserved.
  8. **
  9. **  History:    05-Jan-87       Original Version (1.0)
  10. **        07-Feb-87    Added lock initialization to OpenPipe()
  11. **                 for locks on individual pipes.
  12. **        12-Feb-87    Fixed bug in OpenPipe(): previously ignored
  13. **                 lock passed in packet.  Bug uncovered when
  14. **                 pipes became lockable, and thus assignable.
  15. **        26-Mar-87    Fixed bug in ClosePipe(): not closing r/w
  16. **                 mode properly (extraneous else).
  17. */
  18.  
  19. #include   <libraries/dos.h>
  20. #include   <libraries/dosextens.h>
  21. #include   <libraries/filehandler.h>
  22. #include   <exec/exec.h>
  23.  
  24. #include   "pipelists.h"
  25. #include   "pipename.h"
  26. #include   "pipebuf.h"
  27. #include   "pipecreate.h"
  28. #include   "pipesched.h"
  29. #include   "pipe-handler.h"
  30.  
  31. #if PIPEDIR
  32. # include   "pipedir.h"
  33. #endif PIPEDIR
  34.  
  35. #ifdef DEBUG
  36. # include   "pipedebug.h"
  37. #endif DEBUG
  38.  
  39.  
  40.  
  41. /*---------------------------------------------------------------------------
  42. ** pipecreate.c
  43. ** ------------
  44. ** This module handles opens and closes for pipes.
  45. **
  46. ** Visible Functions
  47. ** -----------------
  48. **    void  OpenPipe    (pkt, tapfh)
  49. **    void  ClosePipe   (pkt)
  50. **    void  DiscardPipe (pipe)
  51. **
  52. ** Macros (in pipecreate.h)
  53. ** ------------------------
  54. **    - none -
  55. **
  56. ** Local Functions
  57. ** ---------------
  58. **    int   TapFormsLoop (tapfh, pipe)
  59. **    void  OpenTap      (pkt, tapname)
  60. **    void  CloseTap     (tapfh)
  61. */
  62.  
  63.  
  64.  
  65. /*---------------------------------------------------------------------------
  66. ** OpenPipe() handles open requests.  The DosPacket from the client and the
  67. ** filehandle of the tap are sent.  If tapfh is 0, but the name sent
  68. ** indicates a tap is desired (see ParsePipeName() in pipename.c), then
  69. ** an OpenTap() request is initiated and OpenPipe() is immediately exited.
  70. ** Later, when the request returns (to HandleTapReply()), OpenPipe() is
  71. ** called again with the same client packet and the newly returned tapfh.
  72. **      If tapfh is nonzero, or if it is zero but no tap is desired, then
  73. ** the an attempt to open the pipe is made.  If a existent pipe with a tap is
  74. ** to be opened and a new tapfh is given, the old tap is closed.
  75. **      If the name's syntax is incorrect, then the request is returned
  76. ** unsuccessful.  Otherwise, if the pipe named by the request does not
  77. ** already exist, a new pipe is created (if there is enough memory).
  78. ** If it does exist, but it is already open for the mode requested, an error
  79. ** is returned (a maximum of one reader and one writer is allowed).
  80. **      A successful open returns the client's filehandle with its Arg1 field
  81. ** pointing to a PIPEKEY, which in turn identifies the pipe and open mode.
  82. **      Unless an OpenTap() is required, the packet is returned to the cleint
  83. ** by this function.  If an OpenTap() is required, it will be returned by the
  84. ** the later call to this function when the tap open request is returned.
  85. **      Note: the code which checks if the lock sent in the packet relies on
  86. ** the fact that the pipe-handler does not allow subdirectories.  If a lock
  87. ** on a pipe is passed in, then that pipe is opened.  Otherwise, the name is
  88. ** parsed without reference to the lock.
  89. */
  90.  
  91. void  OpenPipe (pkt, tapfh)
  92.  
  93. struct DosPacket  *pkt;
  94. BPTR              tapfh;
  95.  
  96. { void               OpenTap(), CloseTap();
  97.   LONG               openmode;
  98.   struct FileHandle  *handle;
  99.   struct FileLock    *lock;
  100.   char               *pipename = NULL, *tapname = NULL;
  101.   ULONG              pipesize;
  102.   PIPEKEY            *pipekey = NULL;
  103.   PIPEDATA           *pipe;
  104.   int                TapFormsLoop();
  105.  
  106.  
  107.   pkt->dp_Res1= 0;     /* error, for now */
  108.  
  109.   if (! ParsePipeName (BPTRtoCptr (pkt->dp_Arg3), &pipename, &pipesize, &tapname))
  110.     { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
  111.       goto OPENREPLY;
  112.     }
  113.  
  114.   if ( (tapfh == 0) && (tapname != NULL) && (tapname[0] != '\0') )
  115.     { OpenTap (pkt, tapname);     /* start tap open request */
  116.       return;                     /* HandleTapReply() re-calls when request returns */
  117.     }
  118.  
  119.   openmode= pkt->dp_Type;
  120.   lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg2);
  121.   pipe= NULL;
  122.  
  123.   if ( (lock == NULL) || ((pipe= (PIPEDATA *) lock->fl_Key) == NULL) )
  124.     { if (pipename[0] == '\0')
  125. #if AUTONAME
  126.         pipename= get_autoname ((openmode == MODE_NEWFILE) || (openmode == MODE_READWRITE));
  127. #else !AUTONAME
  128.         { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
  129.           goto OPENREPLY;
  130.         }
  131. #endif AUTONAME
  132.  
  133.       pipe= FindPipe (pipename);
  134.     }
  135.   else     /* packet's lock was on the pipe */
  136.     { if (pipename[0] != '\0')
  137.         { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
  138.           goto OPENREPLY;
  139.         }
  140.  
  141.       pipename= pipe->name;
  142.     }
  143.  
  144.  
  145.   handle= (struct FileHandle *) BPTRtoCptr (pkt->dp_Arg1);
  146.  
  147.   if ((pipekey= (PIPEKEY *) AllocMem (sizeof (PIPEKEY), ALLOCMEM_FLAGS)) == NULL)
  148.     { pkt->dp_Res2= ERROR_NO_FREE_STORE;
  149.       goto OPENREPLY;
  150.     }
  151.  
  152.  
  153.   if (pipe == NULL)     /* then PIPE NOT FOUND */
  154.     { if (openmode == MODE_READONLY)
  155.         { pkt->dp_Res2= ERROR_OBJECT_NOT_FOUND;
  156.           goto OPENREPLY;
  157.         }
  158.  
  159.       pkt->dp_Res2= ERROR_NO_FREE_STORE;     /* in case of AllocMem error */
  160.  
  161.       if ((pipe= (PIPEDATA *) AllocMem (sizeof (PIPEDATA), ALLOCMEM_FLAGS)) == NULL)
  162.         goto OPENMEMERR1;
  163.  
  164.       if ((pipe->buf= AllocPipebuf (pipesize)) == NULL)
  165.         goto OPENMEMERR2;
  166.  
  167.       if ((pipe->lock= (struct FileLock *) AllocMem (sizeof (struct FileLock), ALLOCMEM_FLAGS)) == NULL)
  168.         { FreePipebuf (pipe->buf);
  169. OPENMEMERR2:
  170.           FreeMem (pipe, sizeof (PIPEDATA));
  171. OPENMEMERR1:
  172.           goto OPENREPLY;
  173.         }
  174.  
  175.       l_strcpy (pipe->name, pipename);
  176.  
  177.       pipekey->pipe=     pipe;
  178.       pipekey->openmode= openmode;
  179.  
  180.       if (openmode == MODE_READONLY)
  181.         { pipekey->iotype= PIPEREAD;
  182.           pipe->flags |=   OPEN_FOR_READ;
  183.         }
  184.       else if (openmode == MODE_NEWFILE)
  185.         { pipekey->iotype= PIPEWRITE;
  186.           pipe->flags=     OPEN_FOR_WRITE;
  187.         }
  188.       else     /* MODE_READWRITE */
  189.         { pipekey->iotype= PIPERW;
  190.           pipe->flags=     (OPEN_FOR_READ | OPEN_FOR_WRITE);
  191.         }
  192.  
  193.       InitList (&pipe->readerlist);
  194.       InitList (&pipe->writerlist);
  195.  
  196.       pipe->tapfh= tapfh;
  197.  
  198. #if PIPEDIR
  199.       pipe->lockct= 0;
  200.       InitLock (pipe->lock, pipe);
  201. #endif PIPEDIR
  202.  
  203.       InsertTail (&pipelist, pipe);     /* at tail for directory's sake */
  204.  
  205. #ifdef DEBUG
  206.        OS ("*** created pipe '"); OS (pipe->name);
  207.        OS ("'   [buflen "); OL (pipe->buf->len); OS ("]\n");
  208. #endif DEBUG
  209.     }
  210.   else     /* PIPE WAS FOUND */
  211.     { if (TapFormsLoop (tapfh, pipe))
  212.         { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
  213.           goto OPENREPLY;
  214.         }
  215.  
  216.       pipekey->pipe=     pipe;
  217.       pipekey->openmode= openmode;
  218.  
  219.       pkt->dp_Res2= ERROR_OBJECT_IN_USE;     /* in case of openmode error */
  220.  
  221.       if (openmode == MODE_READONLY)
  222.         { if (pipe->flags & OPEN_FOR_READ)
  223.             goto OPENREPLY;
  224.  
  225.           pipekey->iotype= PIPEREAD;
  226.           pipe->flags  |=  OPEN_FOR_READ;
  227.         }
  228.       else if (openmode == MODE_NEWFILE)
  229.         { if (pipe->flags & OPEN_FOR_WRITE)
  230.             goto OPENREPLY;
  231.  
  232.           pipekey->iotype= PIPEWRITE;
  233.           pipe->flags  |=  OPEN_FOR_WRITE;
  234.         }
  235.       else     /* MODE_READWRITE */
  236.         { if (pipe->flags & (OPEN_FOR_READ | OPEN_FOR_WRITE))
  237.             goto OPENREPLY;
  238.  
  239.           pipekey->iotype= PIPERW;
  240.           pipe->flags=     (OPEN_FOR_READ | OPEN_FOR_WRITE);
  241.         }
  242.  
  243.       if (tapfh != 0)
  244.         { if (pipe->tapfh != 0)
  245.             CloseTap (pipe->tapfh);     /* close old tap first */
  246.  
  247.           pipe->tapfh= tapfh;
  248.         }
  249.     }
  250.  
  251.  
  252.   handle->fh_Arg1= (LONG) pipekey;     /* for identification on Read, Write, Close */
  253.   pkt->dp_Res1= 1;
  254.   pkt->dp_Res2= 0;     /* for successful open */
  255.  
  256.  
  257. OPENREPLY:
  258.   if (pkt->dp_Res1 == 0)     /* then there was an error */
  259.     { if (pipekey != NULL)
  260.         FreeMem (pipekey, sizeof (PIPEKEY));
  261.  
  262.       if (tapfh != 0)
  263.         CloseTap (tapfh);
  264.     }
  265. #if PIPEDIR
  266.    else
  267.      SetPipeDate (pipe);
  268. #endif PIPEDIR
  269.  
  270.   ReplyPkt (pkt);
  271. }
  272.  
  273.  
  274.  
  275. /*---------------------------------------------------------------------------
  276. ** This routine checks for "the old loop in the pipe trick" (86).  If the
  277. ** handler has a loop through its tap, the handler will endlessly pass
  278. ** packets to itself.  This would be disastrous if the handler is running at
  279. ** high priority.
  280. */
  281.  
  282. static int  TapFormsLoop (tapfh, pipe)
  283.  
  284. BPTR      tapfh;
  285. PIPEDATA  *pipe;
  286.  
  287. { struct FileHandle  *handle;
  288.   PIPEKEY            *tapkey;
  289.   PIPEDATA           *tappipe;
  290.   int                numchecks;     /* protection */
  291.  
  292.  
  293.   for (numchecks= 0; ((tapfh != 0) && (numchecks < 10000)); ++numchecks)
  294.     { handle= (struct FileHandle *) BPTRtoCptr (tapfh);
  295.  
  296.       if (handle->fh_Type == PipePort)     /* then the tap is a pipe, too */
  297.         { if ( ((tapkey= (PIPEKEY *) handle->fh_Arg1) == NULL) ||
  298.                ((tappipe= tapkey->pipe) == NULL)                  )
  299.             return FALSE;
  300.  
  301.           if (tappipe == pipe)
  302.             return TRUE;
  303.  
  304.           tapfh= tappipe->tapfh;
  305.         }
  306.       else
  307.         return FALSE;
  308.     }
  309.  
  310.   return FALSE;
  311. }
  312.  
  313.  
  314.  
  315. /*---------------------------------------------------------------------------
  316. ** The previous open performed on a pipe is terminated.  The PIPEKEY
  317. ** allocated for the client when the pipe was opened is freed.  Then,
  318. ** CheckWaiting() is called -- it will discard the pipe if it becomes empty
  319. ** and is not opened for read or write.
  320. */
  321.  
  322. void  ClosePipe (pkt)
  323.  
  324. struct DosPacket  *pkt;
  325.  
  326. { PIPEKEY   *pipekey;
  327.   PIPEDATA  *pipe;
  328.   void      DeletePipe();
  329.  
  330.  
  331.   pipekey= (PIPEKEY *) pkt->dp_Arg1;
  332.   pipe= pipekey->pipe;
  333.  
  334.   if ((pipekey->iotype == PIPEREAD) || (pipekey->iotype == PIPERW))
  335.     pipe->flags &= ~OPEN_FOR_READ;
  336.  
  337.   if ((pipekey->iotype == PIPEWRITE) || (pipekey->iotype == PIPERW))
  338.     pipe->flags &= ~OPEN_FOR_WRITE;
  339.  
  340.   FreeMem (pipekey, sizeof (PIPEKEY));
  341.  
  342.   CheckWaiting (pipe);     /* will discard if empty */
  343.  
  344.   pkt->dp_Res1= 1;
  345.   pkt->dp_Res2= 0;
  346.  
  347.   ReplyPkt (pkt);
  348. }
  349.  
  350.  
  351.  
  352. /*---------------------------------------------------------------------------
  353. ** Remove a pipe from the pipe list and release its memory.  The pipe is
  354. ** assumed empty and having no clients.
  355. */
  356.  
  357. void  DiscardPipe (pipe)
  358.  
  359. PIPEDATA  *pipe;
  360.  
  361. {
  362. #ifdef DEBUG
  363.   OS ("*** discarding pipe '"); OS (pipe->name); OS ("'\n");
  364. #endif DEBUG
  365.  
  366.   Delete (&pipelist, pipe);
  367.  
  368.   FreePipebuf (pipe->buf);
  369.   FreeMem (pipe->lock, sizeof (struct FileLock));
  370.  
  371.   if (pipe->tapfh != 0)
  372.     CloseTap (pipe->tapfh);
  373.  
  374.   FreeMem (pipe, sizeof (PIPEDATA));
  375. }
  376.  
  377.  
  378.  
  379. /*---------------------------------------------------------------------------
  380. ** An open request for a tap is performed.  A WAITINGDATA structure is
  381. ** allocated to hold the client packet until later.  HandleTapReply() will
  382. ** deal with the reply and, if successful, re-call OpenPipe().
  383. */
  384.  
  385. static void  OpenTap (pkt, tapname)
  386.  
  387. struct DosPacket  *pkt;
  388. char              *tapname;
  389.  
  390. { char               *Bname;
  391.   struct FileHandle  *handle;
  392.   WAITINGDATA        *wd;
  393.   struct DosPacket   *tappkt;
  394.   struct MsgPort     *Handler;
  395.   struct FileLock    *Lock;
  396.   void               StartTapIO();
  397.  
  398.  
  399.   if ( (tapname == NULL) ||
  400.        ((Bname= (char *) AllocMem (OPENTAP_STRSIZE, ALLOCMEM_FLAGS)) == NULL) )
  401.     goto OPENTAPERR;
  402.  
  403.   if ((handle= (struct FileHandle *) AllocMem (sizeof (struct FileHandle), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL)
  404.     goto OPENTAPERR1;
  405.  
  406.   if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL)
  407.     goto OPENTAPERR2;
  408.  
  409.   if ((tappkt= AllocPacket (TapReplyPort)) == NULL)
  410.     goto OPENTAPERR3;
  411.  
  412.   if ((Handler= DeviceProc (tapname)) == NULL)
  413.     { FreePacket (tappkt);
  414. OPENTAPERR3:
  415.       FreeMem (wd, sizeof (WAITINGDATA));
  416. OPENTAPERR2:
  417.       FreeMem (handle, sizeof (struct FileHandle));
  418. OPENTAPERR1:
  419.       FreeMem (Bname, OPENTAP_STRSIZE);
  420. OPENTAPERR:
  421.       pkt->dp_Res1= 0;
  422.       pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
  423.       ReplyPkt (pkt);
  424.       return;
  425.     }
  426.  
  427.   Lock= (struct FileLock *) IoErr ();
  428.   CstrtoBSTR (tapname, Bname, OPENTAP_STRSIZE);
  429.  
  430.   handle->fh_Pos= -1;
  431.   handle->fh_End= -1;
  432.   handle->fh_Type= Handler;     /* initialize file handle */
  433.  
  434.   wd->pkt= tappkt;
  435.   wd->pktinfo.tapwait.clientpkt= pkt;
  436.   wd->pktinfo.tapwait.handle= handle;     /* for HandleTapReply() */
  437.  
  438.   StartTapIO ( tappkt, MODE_NEWFILE,
  439.                CptrtoBPTR (handle), CptrtoBPTR (Lock), CptrtoBPTR (Bname),
  440.                Handler );
  441.  
  442.   InsertHead (&tapwaitlist, wd);
  443. }
  444.  
  445.  
  446.  
  447. /*---------------------------------------------------------------------------
  448. ** A close request for a tap filehandle is initiated.  When HandleTapReply()
  449. ** gets the reply, it merely discards it.
  450. */
  451.  
  452. static void  CloseTap (tapfh)
  453.  
  454. BPTR  tapfh;
  455.  
  456. { struct FileHandle  *taphandle;
  457.   struct DosPacket   *tappkt;
  458.   WAITINGDATA        *wd;
  459.   void               StartTapIO();
  460.  
  461.  
  462.   taphandle= (struct FileHandle *) BPTRtoCptr (tapfh);
  463.  
  464.   if ((tappkt= AllocPacket (TapReplyPort)) == NULL)
  465.     goto CLOSETAPERR;
  466.  
  467.   if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL)
  468.     { FreePacket (tappkt);
  469. CLOSETAPERR:
  470.       FreeMem (taphandle, sizeof (struct FileHandle));
  471. #ifdef DEBUG
  472.       OS ("!!! ERROR - CloseTap() failed\n");
  473. #endif DEBUG
  474.       return;
  475.     }
  476.  
  477.   wd->pkt= tappkt;
  478.   /* don't need ...tapwait.clientpkt */
  479.   wd->pktinfo.tapwait.handle= taphandle;     /* for HandleTapReply() */
  480.  
  481.   StartTapIO ( tappkt, ACTION_END,
  482.                taphandle->fh_Arg1, 0, 0,
  483.                taphandle->fh_Type );
  484.  
  485.   InsertHead (&tapwaitlist, wd);
  486. }
  487.